#include "Layer.hpp"
#include "Bits.h"
#include "Rede.h"
#include <iostream>
#include <boost/thread.hpp>
#include <boost/date_time.hpp>
//#include "Fisico.hpp"
#include "Enlace.hpp"
//#include <qrencode.h>
//#include "QrImage.hpp"
#include "Layer.hpp"
#include <vector>
//#include "Fisico.hpp"
#include "Transporte.h"
#include "Aplicacao.hpp"
#include "Pilha.hpp"
#include "aplicacao/Jogador.hpp"
#include "aplicacao/Jogo.hpp"
#include "aplicacao/Tabuleiro.hpp"


using namespace ufpb::project::network;
using namespace jogodavelharedes;

class Teste : public Layer {

	public:

		Teste(void) : Layer(0) {
		
		};
		~Teste() {};

		void newMessageToSend(Bits* msg) {

			std::cout << "Teste - Nova message pra enviar pra baixo ";
                        msg->println();
		}

		void newReceivedMessage(Bits* msg) {

			std::cout << "Teste - Nova message Recebida ";
                        msg->println();
		}
};

class Teste2 : public Layer {

	public:
	
		Teste2(void) : Layer(0) {
		};

		~Teste2() {};

		void newMessageToSend(Bits* msg) {

//			std::cout << "Teste2 - Nova message pra enviar pra baixo ";
//                        msg->println();
                        getUpLayer()->receive(msg);
		}

		void newReceivedMessage(Bits* msg) {

			std::cout << "Teste2 - Nova message Recebida ";
                        msg->println();
		}
};

boost::mutex m;
boost::mutex pm;

void imprimeTabuleiro(Tabuleiro* t) {

    m.lock();
    for (int i = 0; i < t->getNumeroLinhas(); i++) {

        for (int j = 0; j < t->getNumeroColunas(); j++) {

            std::cout << t->getPeca(i, j) << ' ';
        }

        std::cout << std::endl;
    }
    m.unlock();
}

void funcTC1(Pilha* pi) {

	pi = new Pilha();
    std::cout << "Iniciando jogo C1" << std::endl;
    boost::this_thread::sleep(boost::posix_time::milliseconds(3000));
    
    Jogador* jogador1 = new Jogador('X');
    Jogador* jogador2 = new Jogador('O');
    Jogo* jogo = new Jogo(jogador1, jogador2);

    Jogador* esse = jogador1;

    jogo->iniciar();

    while (!jogo->verificaFimDoJogo()) {

        int j;
        int i;
        Tabuleiro* t = jogo->getTabuleiro();
        imprimeTabuleiro(t);

        std::cout << "Vez do jogador: "
                << (jogo->jogadorDaVez() == jogador1
                    ?"Jogador1"
                    :"Jogador2")
                << std::endl;

        if (esse == jogo->jogadorDaVez()) {
            
            do {

                std::cout << "Digite a linha: ";
                std::cin >> i;
                std::cout << "Digite a coluna: ";
                std::cin >> j;
            } while (!jogo->ehJogadaValida(i, j));

			std::cout << "Fazendo joagada" << std::endl;
            jogo->fazerJogada(i, j);
            unsigned char ci = i + '0';
            unsigned char cj = j + '0';
			std::cout << "Escrevendo" << pi << std::endl;
            pi->escreve(0, 1, &ci);
            pi->escreve(0, 1, &cj);
        } else {

            //Espera a jogador do outro jogador
			std::cout << "esperando jogada" << std::endl;
            unsigned char* jog = new unsigned char[2];
            pi->le(jog, 2);
            std::cout << "Recebeu jogada" << std::endl;
            int i = jog[0] - '0';
            int j = jog[1] - '0';
            jogo->fazerJogada(i, j);
        }
    }

    imprimeTabuleiro(jogo->getTabuleiro());
    if (jogo->houveVencedor()) {

        std::cout << "Vencedor: "
                << (jogo->getVencedor() == jogador1
                    ?"Jogador1"
                    :"Jogador2") << std::endl;
    } else {

        std::cout << "Deu velha. =D" << std::endl;
    }
    delete jogo;
    delete jogador1;
    delete jogador2;

    while (true);
}


void testarTudo() {
    
	
	Pilha *pilha = new Pilha();

	/*unsigned char ch = 'a';
	//unsigned char* b = (unsigned char*) "1234567";
	//unsigned char ch2 = 'b';
	unsigned char ch2 = '9';
	pilha->escreve(0,1,&ch);
	ch = 'r';
	pilha->escreve(0,1,&ch);
	
	pilha->escreve(0,1,&ch2);

	unsigned char cj;
	//unsigned char cl;
	//pilha->le(&cj, 1);
	//std::cout << cj << std::endl;
	//pilha->le(&cj, 1);
	//std::cout << cj << std::endl;

	for (int i = 0; i < 3; i++) {

		pilha->le(&cj, 1);
		std::cout << cj << std::endl;
	}*/

	std::cout << "Done" << std::endl;

	boost::thread(&funcTC1, pilha);

	
	//delete pilha;
	while(true){}
}

/*void testarFisicoComResto() {
	Transporte *transporte = new Transporte();
	    Enlace *enlace = new Enlace(14);
	    map<string, string> mapa;
	    mapa["meuIP"] = "5";
	    mapa["mac"] = "14";
	    mapa["souOGateway"] = "false";
	    mapa["mapa"] = "4-13,5-14";

	    Rede *rede = new Rede(&mapa);
	    Fisico *fisico = new Fisico();

	    Teste *teste = new Teste();

	    transporte->setDownLayer(rede);
	    rede->setDownLayer(enlace);
	    enlace->setDownLayer(fisico);
	    fisico->setUpLayer(enlace);
	    rede->setUpLayer(transporte);
	    enlace->setUpLayer(rede);
	    transporte->setUpLayer(teste);
	    fisico->init();
	    sleep(3);
	    enlace->init();
	    transporte->init();
	    teste->init();

	    rede->init();


	    Bits* msg = new Bits(120);
	    int ipDestino = 5;
	    string str = "oi";
	    msg->putInfo(Transporte::IP_OFFSET, Transporte::IP_LENGTH, ipDestino);
	    msg->putInfo(4, 16, 123);
//	    transporte->send(msg);
	    while(true){}
}

void testRede() {
    Teste* t = new Teste();
    t->init();
    
    Bits* msgPraBaixo = new Bits(8);
    Bits* msgPraCima = new Bits(16);
    int ipDestino = 5;
    int macDestino = 10;
    int meuIP = 2;
    int payLoad = 10;
    
    msgPraBaixo->putInfo(0,4,ipDestino);
    msgPraBaixo->putInfo(4,4,payLoad);
    
    msgPraCima->putInfo(0,4,macDestino);
    msgPraCima->putInfo(4,4,meuIP);
    msgPraCima->putInfo(8,4,ipDestino);
    msgPraCima->putInfo(12,4,payLoad);
    
    Rede* r = new Rede();
    r->init();
    r->setDownLayer(t);
    r->setUpLayer(t);
    while(true) {
        r->send(msgPraBaixo);
        sleep(2);
        r->receive(msgPraCima);
        sleep(2);
        
    }
}

void printQr(unsigned char* g, int width) {

	for (int i = 0; i < width; i++) {

		for (int j = 0; j < width; j++) {

			if (g[i * width + j] & 0 == 0) {

				printf("%c", ' ');
			} else {

				printf("%c", '.');
			}
		}
		putchar('\n');
	}
}*/

//int main(int argc, char* argv[]) {
int main(int argc, char* argv[]) {

//testarFisicoComResto();

testarTudo();
//	char* string = "11223344556677889900";
//	QRcode* code = QRcode_encodeString8bit(string, 2, QR_ECLEVEL_L );
//
//	printf("%d - %p\n", errno, code);
//	printf("width: %d\n", code->width);
//	printf("version: %d\n", code->version);
//	printf("%d\n",code->data[0] & 0);
//
//	printQr(code->data, code->width);
//
//	QrImage* qr = new QrImage(code->data, code->width);
//
//
//	Imagem* teste = qr->getImage()->resize(10);
//
//	Imagem* resultado = new Imagem(teste->width()+100, teste->height()+100,1);
//	resultado->setAllPixels(255);
//	resultado->add(teste, 50, 50);
//
//	cvNamedWindow( "result", CV_WINDOW_AUTOSIZE );
//	cvShowImage( "result",resultado->getIplImage() );
//	cvWaitKey( 100 );

	//const char* tostr = std::string("berg55igor").c_str();
	//int len = strlen(tostr);




	/*Fisico *fisico = new Fisico();
	//Enlace * enlace = new Enlace();

	//fisico->setUpLayer(enlace);
	//enlace->setDownLayer(fisico);

	Bits* b = new Bits(16);
	Bits* b1 = new Bits(16);

	b->set(0, 0);
	b->set(1, 0);
	b->set(2, 1);
	b->set(3, 1);
	b->set(4, 0);
	b->set(5, 0);
	b->set(6, 1);
	b->set(7, 0);

	b->set(0+8, 0);
	b->set(1+8, 1);
	b->set(2+8, 0);
	b->set(3+8, 0);
	b->set(4+8, 0);
	b->set(5+8, 0);
	b->set(6+8, 1);
	b->set(7+8, 0);

	b1->set(0, 1);
	b1->set(1, 0);
	b1->set(2, 1);
	b1->set(3, 1);
	b1->set(4, 0);
	b1->set(5, 1);
	b1->set(6, 0);
	b1->set(7, 0);

	b1->set(0+8, 1);
	b1->set(1+8, 1);
	b1->set(2+8, 0);
	b1->set(3+8, 0);
	b1->set(4+8, 1);
	b1->set(5+8, 0);
	b1->set(6+8, 0);
	b1->set(7+8, 1);
	cout<<"oi";

	//enlace->init();
	fisico->init();

//	while (true) {
		//enlace->getDownLayer()->send(b);
//		enlace->getDownLayer()->send(b);
//		enlace->getDownLayer()->send(b);

	char* tostr = "1234587890";
	int l = strlen(tostr);
	Bits* bs = new Bits(l * 8);
	for (int i = 0; i < l; i++) {

			int mask = 0x80;
			bs->set(i*8, tostr[i] & mask);
			mask = mask >> 1;
			bs->set(i*8+1, tostr[i] & mask);
			mask = mask >> 1;
			bs->set(i*8+2, tostr[i] & mask);
			mask = mask >> 1;
			bs->set(i*8+3, tostr[i] & mask);
			mask = mask >> 1;
			bs->set(i*8+4, tostr[i] & mask);
			mask = mask >> 1;
			bs->set(i*8+5, tostr[i] & mask);
			mask = mask >> 1;
			bs->set(i*8+6, tostr[i] & mask);
			mask = mask >> 1;
			bs->set(i*8+7, tostr[i] & mask);

		}

	fisico->send(new Bits("testando.."));
//	bs->println();

	for(int i = 0; i < 6; ++i){

		fisico->send(b);

		cout<<"oi";

		fisico->send(b1);

		cout<<"oi";

		//fisico->send(b);
	}


//		enlace->getDownLayer()->send(b);
//	fisico->newMessageToSend(b);
//	}
//    testRede();

	while(true);
*/
}
